package org.naxx.security.compiler.impl;

import java.util.Arrays;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

import org.apache.log4j.Logger;
import org.naxx.security.compiler.XacmlCompiler;
import org.naxx.security.util.Assert;
import org.naxx.security.util.FileSystemUtil;
import org.naxx.security.util.Util;

public final class XacmlCompilerImpl implements XacmlCompiler {

	private static final Logger logger = Logger.getLogger(XacmlCompilerImpl.class);

	private final JavaCompiler compiler;

	public XacmlCompilerImpl() {
		this.compiler = ToolProvider.getSystemJavaCompiler();
		Assert.assertNotNull(compiler,
				"System compiler provided by this platform is null");
	}

	/**
	 * TODO optimize performance, cache FileManager?
	 * provide Writer so we can detect diagnostic messages
	 * written directly to Writer
	 */
	@Override
	public void compile(String[] sourceFileNames) throws Exception {
		StandardJavaFileManager fileManager = null;
		try {
			logger.info("Preparing to compile following Java files '"
					+ Util.format(sourceFileNames) + "'");

			DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
			fileManager = compiler.getStandardFileManager(diagnostics, null, null);

			Iterable<? extends JavaFileObject> compilationUnits1 = fileManager
					.getJavaFileObjectsFromStrings(Arrays
							.asList(sourceFileNames));

			CompilationTask task = compiler.getTask(null, fileManager, null,
					null, null, compilationUnits1);

			Boolean result = task.call();

			logger.info("Compilation was '"
					+ (result.booleanValue() ? "successful" : "unsuccessful")
					+ "'");

			logger.info("Found '" + diagnostics.getDiagnostics().size()
					+ "' diagnostic reports...");
			for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics
					.getDiagnostics()) {
				logger.info("Error on line '" + diagnostic.getLineNumber()
						+ "' in source '" + diagnostic.getSource().toUri() + "'");
			}
		} finally {
			FileSystemUtil.close(fileManager);
		}
	}
}
